package com.nx.platform.es.common.utils;

import com.google.common.base.Strings;
import com.google.common.primitives.Doubles;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import org.apache.commons.lang3.math.NumberUtils;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author
 * @since Dec 16, 2015
 */
public class MoreFunctions {

    public static String[] toStringArray(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(String::trim).filter(s -> s.length() > 0).toArray(String[]::new);
    }

    public static String[] toStringArray(Collection<?> collection) {
        return collection.stream().map(String::valueOf).map(String::trim).filter(s -> s.length() > 0).toArray(String[]::new);
    }

    public static String[] toStringArray(Object[] arr) {
        return Stream.of(arr).map(String::valueOf).map(String::trim).filter(s -> s.length() > 0).toArray(String[]::new);
    }

    public static Set<String> toStringSet(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(String::trim).filter(s -> s.length() > 0).collect(Collectors.toSet());
    }

    public static Set<String> toStringSet(Collection<?> collection) {
        return collection.stream().map(String::valueOf).map(String::trim).filter(s -> s.length() > 0).collect(Collectors.toSet());
    }

    public static Set<String> toStringSet(Object[] arr) {
        return Stream.of(arr).map(String::valueOf).map(String::trim).filter(s -> s.length() > 0).collect(Collectors.toSet());
    }

    public static List<String> toStringList(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(String::trim).filter(s -> s.length() > 0).collect(Collectors.toList());
    }

    public static List<String> toStringList(Collection<?> collection) {
        return collection.stream().map(String::valueOf).map(String::trim).filter(s -> s.length() > 0).collect(Collectors.toList());
    }

    public static List<Object> toObjectList(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(String::trim).filter(s -> s.length() > 0)
                .map(str -> NumberUtils.isDigits(str) ? Longs.tryParse(str) : (NumberUtils.isNumber(str) ? Doubles.tryParse(str) : str))
                .collect(Collectors.toList());
    }

    public static List<Object> toObjectList(Collection<?> collection) {
        return collection.stream().map(String::valueOf).map(String::trim).filter(s -> s.length() > 0)
                .map(str -> NumberUtils.isDigits(str) ? Longs.tryParse(str) : (NumberUtils.isNumber(str) ? Doubles.tryParse(str) : str))
                .collect(Collectors.toList());
    }

    public static List<String> toStringList(Object[] arr) {
        return Stream.of(arr).map(String::valueOf).map(String::trim).filter(s -> s.length() > 0).collect(Collectors.toList());
    }

    public static Long[] toLongArray(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Longs::tryParse).filter(Objects::nonNull).toArray(Long[]::new);
    }

    public static Long[] toLongArray(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToLong).filter(Objects::nonNull).toArray(Long[]::new);
    }

    public static Long[] toLongArray(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToLong).filter(Objects::nonNull).toArray(Long[]::new);
    }

    public static Set<Long> toLongSet(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Longs::tryParse).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static Set<Long> toLongSet(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToLong).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static Set<Long> toLongSet(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToLong).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static List<Long> toLongList(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Longs::tryParse).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static List<Long> toLongList(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToLong).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static List<Long> toLongList(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToLong).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static Integer[] toIntegerArray(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Ints::tryParse).filter(Objects::nonNull).toArray(Integer[]::new);
    }

    public static Byte[] toByteArray(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToByte).filter(Objects::nonNull).toArray(Byte[]::new);
    }

    public static Byte[] toByteArray(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToByte).filter(Objects::nonNull).toArray(Byte[]::new);
    }

    public static Set<Byte> toByteSet(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToByte).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static Set<Byte> toByteSet(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToByte).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static List<Byte> toByteList(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToByte).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static List<Byte> toByteList(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToByte).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static Integer[] toIntegerArray(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToInteger).filter(Objects::nonNull).toArray(Integer[]::new);
    }

    public static Integer[] toIntegerArray(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToInteger).filter(Objects::nonNull).toArray(Integer[]::new);
    }

    public static Set<Integer> toIntegerSet(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Ints::tryParse).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static Set<Integer> toIntegerSet(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToInteger).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static Set<Integer> toIntegerSet(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToInteger).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static List<Integer> toIntegerList(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Ints::tryParse).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static List<Integer> toIntegerList(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToInteger).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static List<Integer> toIntegerList(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToInteger).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static Double[] toDoubleArray(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Doubles::tryParse).filter(Objects::nonNull).toArray(Double[]::new);
    }

    public static Double[] toDoubleArray(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToDouble).filter(Objects::nonNull).toArray(Double[]::new);
    }

    public static Double[] toDoubleArray(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToDouble).filter(Objects::nonNull).toArray(Double[]::new);
    }

    public static Set<Double> toDoubleSet(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Doubles::tryParse).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static Set<Double> toDoubleSet(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToDouble).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static Set<Double> toDoubleSet(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToDouble).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    public static List<Double> toDoubleList(String string, Pattern splitter) {
        return splitter.splitAsStream(Strings.nullToEmpty(string)).map(Doubles::tryParse).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static List<Double> toDoubleList(Collection<?> collection) {
        return collection.stream().map(MoreFunctions::objectToDouble).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static List<Double> toDoubleList(Object[] arr) {
        return Stream.of(arr).map(MoreFunctions::objectToDouble).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static Byte objectToByte(Object obj) {
        if (obj instanceof Byte) {
            return (Byte) obj;
        } else if (obj instanceof Number) {
            return ((Number) obj).byteValue();
        } else {
            Integer i = Ints.tryParse(String.valueOf(obj));
            return i != null ? i.byteValue() : null;
        }
    }

    public static Integer objectToInteger(Object obj) {
        if (obj instanceof Integer) {
            return (Integer) obj;
        } else if (obj instanceof Number) {
            return ((Number) obj).intValue();
        } else {
            return Ints.tryParse(String.valueOf(obj));
        }
    }

    public static Long objectToLong(Object obj) {
        if (obj instanceof Long) {
            return (Long) obj;
        } else if (obj instanceof Number) {
            return ((Number) obj).longValue();
        } else {
            return Longs.tryParse(String.valueOf(obj));
        }
    }

    public static Double objectToDouble(Object obj) {
        if (obj instanceof Double) {
            return (Double) obj;
        } else if (obj instanceof Number) {
            return ((Number) obj).doubleValue();
        } else {
            return Doubles.tryParse(String.valueOf(obj));
        }
    }

    public static Boolean objectToBoolean(Object obj) {
        if (obj instanceof Boolean) {
            return (Boolean) obj;
        } else if (obj instanceof Number) {
            return ((Number) obj).intValue() == 1;
        } else {
            return "true".equals(String.valueOf(obj));
        }
    }

    public static Object stringToObject(String str) {
        return NumberUtils.isDigits(str) ? Longs.tryParse(str) :
                (NumberUtils.isNumber(str) ? Doubles.tryParse(str) : str);
    }

}
